package com.yuanmei.charts;

import android.content.Context;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;

import com.github.mikephil.charting.charts.ScatterChart;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.data.ScatterData;
import com.github.mikephil.charting.data.ScatterDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.interfaces.datasets.IScatterDataSet;
import com.yuanmei.model.AmountStat;
import com.yuanmei.views.R;
import com.yuanmei.model.TickQuote;
import com.yuanmei.common.Utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

public class TickQuoteDataSet implements TaChartData {
    private static String TAG = TickQuoteDataSet.class.getName();
    private List<String> mXAxisTick;
    private List<Float> mVolumeList;
    private List<Float> mAmountList;
    private List<String> mTypeList;
    private List<Float> mPriceList;
    private CombinedData mAmountCombineData;
    private CombinedData mTimeSharePriceData;
    private List<TickQuote> mDescendTickQuotes;
    private List<TickQuote> mAescendTickQuotes;

    private float mTotalAmount;
    private Context mContext;
    List<AmountStat> mAmountStatList;

    public TickQuoteDataSet(Context context, List<TickQuote> tickQuotes, float yClose) {
        mContext = context;
        mAescendTickQuotes = tickQuotes;
        mDescendTickQuotes = new ArrayList<>();
        mXAxisTick = new ArrayList<>();
        mVolumeList = new ArrayList<>();
        mAmountList = new ArrayList<>();
        mTypeList = new ArrayList<>();
        mPriceList = new ArrayList<>();

        List<BarEntry> amountBarList = new ArrayList<>();
        List<Entry> priceLineList = new ArrayList<>();
        List<Entry> averagePriceLineList = new ArrayList<>();
        List<Entry> averageAmountLineList = new ArrayList<>();
        List<Entry> yCloseLineList = new ArrayList<>();
        List<Integer> amountColors = new ArrayList<>();
        HashMap<Float, AmountStat> amountStatMap = new HashMap<>();

//        int green = Color.rgb(110, 190, 102);
//        int red = Color.rgb(211, 74, 88);
//        int blue = Color.rgb(160, 135, 95);
        int green = mContext.getResources().getColor(R.color.seal_deals_color);
        int red = mContext.getResources().getColor(R.color.buy_deals_color);
        int blue = mContext.getResources().getColor(R.color.unknown_deals_color);
        float maxQuoteAmount = 0;
        float minQuoteAmount = Float.MAX_VALUE;
        float totalVolume = 0;
        float totalAmount = 0;
        int tradedDeals = tickQuotes.size();
        for (int i = 0; i < tradedDeals; i++) {
            mDescendTickQuotes.add(tickQuotes.get(tradedDeals - 1 - i));
            TickQuote quote = tickQuotes.get(i);
            String tickString = Utils.formatStringFromTick(quote.getTick());
            mXAxisTick.add(tickString);
            float volume = quote.getVolume();
            mVolumeList.add(volume);

            float amount = quote.getAmount();
            mAmountList.add(amount);
            maxQuoteAmount = Math.max(amount, maxQuoteAmount);
            minQuoteAmount = Math.min(amount, minQuoteAmount);
            amountBarList.add(new BarEntry(i, amount));

            String type = quote.getType();
            mTypeList.add(type);
            if (type.equalsIgnoreCase("买盘")) {
                amountColors.add(red);
            } else if (type.equalsIgnoreCase("卖盘")) {
                amountColors.add(green);
            } else {
                amountColors.add(blue);
            }

            totalVolume += volume;
            totalAmount += amount;
            averagePriceLineList.add(new Entry(i, totalAmount / totalVolume));
            averageAmountLineList.add(new Entry(i, totalAmount / (i + 1)));
            if (yClose > 0) {
                yCloseLineList.add(new Entry(i, yClose));
            }

            float price = quote.getPrice();
            mPriceList.add(price);
            priceLineList.add(new Entry(i, quote.getPrice()));

            if (amountStatMap.containsKey(amount)) {
                AmountStat stat = amountStatMap.get(amount);
                int newCount = stat.getCount() + 1;
                stat.setCount(newCount);
            } else {
                amountStatMap.put(amount, new AmountStat(amount, volume, 1));
            }
        }

        mAmountStatList = new ArrayList<>(amountStatMap.values());
        Collections.sort(mAmountStatList,
                (self, other) -> (Float.compare(other.getAmount(), self.getAmount())));

        mTotalAmount = totalAmount;
        TickQuote lastQuote = tickQuotes.get(tradedDeals - 1);
        TickQuote firstQuote = tickQuotes.get(0);
        if (lastQuote.getTick() < 150000) {
            // Tick 数量自动预测和扩展，让分时界面好看一些
            float tradedSeconds = Utils.minusOfTick(firstQuote.getTick(), lastQuote.getTick());
            if (lastQuote.getTick() >= 130000) {
                // minus 11:30:00 - 13:00:00
                tradedSeconds = tradedSeconds - Utils.SECONDS_PER_HOUR * 1.5f;
            }
            float dealsPerSecond = (float) tradedDeals / tradedSeconds;
            float secondPerDeal = 1.0f / dealsPerSecond;
            int xAppendCount = (int) ((Utils.TRADE_SECONDS_FULL_DAY - tradedSeconds) * dealsPerSecond);
            int startTick = lastQuote.getTick();
            ArrayList<String> appendList = new ArrayList<>();
            try {
                for (int i = 1; i <= xAppendCount; i++) {
                    int tick = Utils.addSecondToTick(startTick, (int) (i * secondPerDeal));
                    if (tick > 113000) {
                        // 加1.5小时，确保时间值准确
                        tick = Utils.addSecondToTick(tick, (int)(Utils.SECONDS_PER_HOUR * 1.5f));
                    }
                    String tickString = Utils.formatStringFromTick(tick);
                    appendList.add(tickString);
                }
                mXAxisTick.addAll(appendList);
            } catch (OutOfMemoryError e) {
                String detailMsg = "Append extra ticks oom fail, xAppendCount=" + xAppendCount +
                        ", startTick=" + startTick + " mXAxisTick.size=" + mXAxisTick.size() +
                        ", appendList.size=" + appendList.size();
                Log.e(TAG, detailMsg);
                throw (new OutOfMemoryError(e.toString() + detailMsg));
            }
        }

        ArrayList<ILineDataSet> priceLineSets = new ArrayList<>();
        LineDataSet priceLine = new LineDataSet(priceLineList, "price");
        TaLib.setCommonMaStyle(priceLine);
        priceLine.setHighlightEnabled(true);
        priceLine.setDrawHorizontalHighlightIndicator(true);
        priceLine.setDrawVerticalHighlightIndicator(true);
        priceLine.setHighLightColor(mContext.getResources().getColor(R.color.border_color));
        priceLine.setColor(mContext.getResources().getColor(R.color.ma5));
        priceLineSets.add(priceLine);

        LineDataSet averagePriceLine = new LineDataSet(averagePriceLineList, "average price");
        TaLib.setCommonMaStyle(averagePriceLine);
        averagePriceLine.setColor(mContext.getResources().getColor(R.color.ma10));
        priceLineSets.add(averagePriceLine);

        LineDataSet yClosePriceLine = new LineDataSet(yCloseLineList, "yestoday close");
        TaLib.setCommonMaStyle(yClosePriceLine);
        yClosePriceLine.setColor(mContext.getResources().getColor(R.color.yes_today_close));
        priceLineSets.add(yClosePriceLine);

        mTimeSharePriceData = new CombinedData();
        mTimeSharePriceData.setData(new LineData(priceLineSets));

        // Amount bar chart
        mAmountCombineData = new CombinedData();
        BarDataSet barSet = new BarDataSet(amountBarList, "Amount");
        barSet.setHighlightEnabled(true);
        barSet.setHighLightAlpha(255);
        barSet.setHighLightColor(mContext.getResources().getColor(R.color.border_color));
        barSet.setDrawValues(false);
        barSet.setColors(amountColors);
        barSet.setValueTextColors(amountColors);
        barSet.setBarBorderWidth(0.0f);
        BarData barData = new BarData(barSet);
        barData.setBarWidth(5f);
        mAmountCombineData.setData(barData);

        ArrayList<ILineDataSet> averageAmountLineSet = new ArrayList<>();
        LineDataSet averageAmountLine = new LineDataSet(averageAmountLineList, "price");
        TaLib.setCommonMaStyle(averageAmountLine);
        averageAmountLine.setHighlightEnabled(true);
        averageAmountLine.setDrawHorizontalHighlightIndicator(true);
        averageAmountLine.setDrawVerticalHighlightIndicator(true);
        averageAmountLine.setHighLightColor(mContext.getResources().getColor(R.color.border_color));
        averageAmountLine.setColor(mContext.getResources().getColor(R.color.ma5));
        averageAmountLineSet.add(averageAmountLine);
        mAmountCombineData.setData(new LineData(averageAmountLineSet));
    }

    private float mDivideQuoteAmount;
    private float mDivideQuoteVolume;

    public float getDivideAmount() {
        return mDivideQuoteAmount;
    }

    public float getDivideVolume() {
        return mDivideQuoteVolume;
    }

    public void rebuildScatterData(float scale) {
        float sumBigAmounts = 0;
        float scaleAmount = scale * mTotalAmount;
        for (int i = 0; i < mAmountStatList.size(); i++) {
            float amount = mAmountStatList.get(i).getAmount();
            sumBigAmounts += amount * mAmountStatList.get(i).getCount();
            if (sumBigAmounts >= scaleAmount) {
                mDivideQuoteAmount = mAmountStatList.get(i).getAmount();
                mDivideQuoteVolume = mAmountStatList.get(i).getVolume();
                break;
            }
        }

        ArrayList<Entry> buyDeals = new ArrayList<>();
        ArrayList<Entry> sellDeals = new ArrayList<>();
        ArrayList<Entry> unknownDeals = new ArrayList<>();
        int quotesCount = mAescendTickQuotes.size();
        for (int i = 0; i < quotesCount; i++) {
            if (mAescendTickQuotes.get(i).getAmount() > mDivideQuoteAmount) {
                String type = mAescendTickQuotes.get(i).getType();
                if (type.equalsIgnoreCase("买盘")) {
                    buyDeals.add(new Entry(i, mAescendTickQuotes.get(i).getPrice()));
                } else if (type.equalsIgnoreCase("卖盘")) {
                    sellDeals.add(new Entry(i, mAescendTickQuotes.get(i).getPrice()));
                } else {
                    unknownDeals.add(new Entry(i, mAescendTickQuotes.get(i).getPrice()));
                }
            }
        }

        int shapeSize = 15;
        ArrayList<IScatterDataSet> scatterDataSets = new ArrayList<IScatterDataSet>();
        if (buyDeals.size() > 0) {
            ScatterDataSet buyDealsSet = new ScatterDataSet(buyDeals, "BuyDeals");
            buyDealsSet.setScatterShape(ScatterChart.ScatterShape.CHEVRON_UP);
            buyDealsSet.setColor(mContext.getResources().getColor(R.color.increasing_color));
            buyDealsSet.setScatterShapeSize(shapeSize);
            scatterDataSets.add(buyDealsSet);
        }

        if (sellDeals.size() > 0) {
            ScatterDataSet sellDealsSet = new ScatterDataSet(sellDeals, "SellDeals");
            sellDealsSet.setScatterShape(ScatterChart.ScatterShape.CHEVRON_DOWN);
            sellDealsSet.setColor(mContext.getResources().getColor(R.color.decreasing_color));
            sellDealsSet.setScatterShapeSize(shapeSize);;
            scatterDataSets.add(sellDealsSet);
        }

        if (unknownDeals.size() > 0) {
            ScatterDataSet unknownDealsSet = new ScatterDataSet(unknownDeals, "UnknownDeals");
            unknownDealsSet.setScatterShape(ScatterChart.ScatterShape.CIRCLE);
            unknownDealsSet.setColor(mContext.getResources().getColor(R.color.unknown_deals_color));
            unknownDealsSet.setScatterShapeSize(shapeSize);
            scatterDataSets.add(unknownDealsSet);
        }

        mTimeSharePriceData.setData(new ScatterData(scatterDataSets));
    }

    @Override
    public int getXAxisSize() {
        return mXAxisTick.size();
    }

    // 这是整个数据集可画的TICK数量，在交易时间里，里面会包含扩展TICK(没有实际交易数据)
    @Override
    public String getXAxisLabel(int index) {
        String xLabel = "None";
        if (index >= 0 && index < mXAxisTick.size()) {
            xLabel = mXAxisTick.get(index);
        }
        return xLabel;
    }

    @Override
    public Spanned getDescription(int index) {
        return Html.fromHtml("TimeShareTicks");
    }

    @Override
    public List<String> getXAxisLabelList() {
        return mXAxisTick;
    }

    public int getRealTickQuoteSize() {
        return mAescendTickQuotes.size();
    }

    public float getVolume(int index) {
        if (index >= 0 && index < mVolumeList.size()) {
            return mVolumeList.get(index);
        }
        return 0.0f;
    }

    public float getAmount(int index) {
        if (index >= 0 && index < mAmountList.size()) {
            return mAmountList.get(index);
        }
        return 0.0f;
    }

    public float getPrice(int index) {
        if (index >= 0 && index < mPriceList.size()) {
            return mPriceList.get(index);
        }
        return 0.0f;
    }

    public String getType(int index) {
        if (index >= 0 && index < mTypeList.size()) {
            return mTypeList.get(index);
        }
        return "None";
    }

    public List<TickQuote> getDescendTickQuotes() {
        return mDescendTickQuotes;
    }

    public String getLastTick() {
        if (mDescendTickQuotes == null || mDescendTickQuotes.size() <= 0) {
            return "";
        }
        return Utils.formatStringFromTick(mDescendTickQuotes.get(0).getTick());
    }

    public int mapDescendIndexToAscendIndex(int descendIndex) {
        if (descendIndex >= 0 && descendIndex < mDescendTickQuotes.size()) {
            TickQuote quote = mDescendTickQuotes.get(descendIndex);
            return mAescendTickQuotes.indexOf(quote);
        } else {
            return -1;
        }
    }

    @Override
    public CombinedData getTaChartData() {
        return mTimeSharePriceData;
    }

    public CombinedData getAmountChartData() {
        return mAmountCombineData;
    }
}
